﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DriveBeamEditor.Controls.BeamNG.Forms;
using DriveBeamEditor.Controls.BeamNG.SectionControls;
using DriveBeamEditor.Controls.General;
using DriveBeamEditor.Properties;
using GBlastImaging;
using JBeamLibrary;
using JBeamLibrary.VehicleParts;
using NativeLibrary;
using DriveBeamEditor.Controls.BeamNG.VehiclePartConfig;

namespace DriveBeamEditor.Forms
{
    public partial class TestForm : Form, IMessageFilter
    {
        #region Fields

        private Vehicle _selectedVehicle = null;

        /* Lets hard-code these so that code must be edited to change them ;) */
        private static readonly string ForumUrl = @"http://www.beamng.com/threads/6223";
        private static readonly string WikiPage = @"http://wiki.beamng.com/Real-Time_Vehicle_Editor_Guide";

        #endregion

        #region Properties

        #endregion

        #region CTORs

        public TestForm()
        {
            InitializeComponent();
            SetStyle(
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.DoubleBuffer |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.SupportsTransparentBackColor |
                ControlStyles.UserPaint,
                true
            );
            Application.AddMessageFilter(this);
        }

        #endregion

        #region Methods

        private void SelectVehicle(Vehicle vehicle)
        {
            /* If null, automatically select the first one */
            if (vehicle == null)
            {
                vehicleContainer.Pull();
            }

            /* Set selected vehicle */
            _selectedVehicle = vehicle;

            /* Bind to controls */
            vehicleHierarchyControl.Vehicle = vehicle;
            configuratorControl.Vehicle = vehicle;
            gameControl.Vehicle = vehicle;
            pcVehicle.CurrentVehicle = vehicle;

            /* Reset the current part on vehicle part controls */
            SelectVehiclePart(null);

            /* Auto select next loaded vehicle */
            if (vehicle == null && vehiclesMenu.ItemCount > 0)
                vehiclesMenu.SelectItemAt(0);

            /* Open correct pane */
            if (vehicle == null)
                vehicleContainer.Pull();
            else
                vehicleContainer.CollapsePanel2();

            /* Hide the webBrowser if needed */
            if (backgroundContainer.Panel2Collapsed)
            {
                backgroundContainer.Panel1Collapsed = true;
            }
        }

        private void SelectVehiclePart(VehiclePart part)
        {
            vehiclePartConfigControl.VehiclePart = part;
            propsControl.VehiclePart = part;
            nodesControl.VehiclePart = part;
            beamsControl.VehiclePart = part;
            flexbodiesControl.VehiclePart = part;
            camerasControl.VehiclePart = part;
            engineControl.VehiclePart = part;
            differentialsControl.VehiclePart = part;
            hubWheelsControl.VehiclePart = part;
            trianglesControl.VehiclePart = part;
            hydrosControl.VehiclePart = part;
            thrustersControl.VehiclePart = part;
            glowMapControl.VehiclePart = part;
            tiesControl.VehiclePart = part;
            nodeBeam3DEditorControl.VehiclePart = part;
        }

        private bool CheckLogin()
        {
            /* Alright now I do not care anymore, just all get in even if you don't have the game... */
            return true;
#if DEBUG
            return true;
#else
            return (!webBrowser.DocumentText.Contains("nouser") && webBrowser.DocumentText.Contains("isuser"));
#endif
        }

        private void SetMaxSize()
        {
            xbMaxSize.Text = @"-";

            SuspendLayout();

            /* Change logo */
            BackgroundImage = Resources.IconRTVE32;

            /* Hide buttons */
            xbGotoForum.Visible = false;
            xbWebsite.Visible = false;

            /* Move menu buttons */
            xbVehicle.Location = new Point(38, 3);
            xbParts.Location = new Point(212, 3);
            xbPreferences.Location = new Point(386, 3);

            /* Move donation items */
            labelDonate.Location = new Point(ClientSize.Width - donateButton.Width - donateButton.Margin.Right - labelDonate.Margin.Left - labelDonate.Width - 350, 6);
            donateButton.Location = new Point(ClientSize.Width - donateButton.Width - donateButton.Margin.Right - 350, 6);

            /* Hide vehicles bar */
            vehiclesMenu.Visible = false;

            /* Move & resize container */
            backgroundContainer.Location = new Point(9, 50);
            backgroundContainer.Size = new Size(ClientSize.Width - 18, ClientSize.Height - 51);

            ResumeLayout(true);
        }

        private void SetNormalSize()
        {
            xbMaxSize.Text = @"+";

            SuspendLayout();

            /* Show buttons */
            xbGotoForum.Visible = true;
            xbWebsite.Visible = true;

            /* Reset menu buttons */
            xbVehicle.Location = new Point(169, 103);
            xbParts.Location = new Point(343, 103);
            xbPreferences.Location = new Point(517, 103);

            /* Move donation items */
            labelDonate.Location = new Point(ClientSize.Width - donateButton.Width - donateButton.Margin.Right - labelDonate.Margin.Left - labelDonate.Width, 50);
            donateButton.Location = new Point(ClientSize.Width - donateButton.Width - donateButton.Margin.Right, 50);

            /* Hide vehicles bar */
            vehiclesMenu.Visible = true;

            /* Move & resize container */
            backgroundContainer.Location = new Point(9, 151);
            backgroundContainer.Size = new Size(ClientSize.Width - 18, ClientSize.Height - 163);

            /* Reset logo */
            BackgroundImage = Resources.TitleBar2;

            ResumeLayout(true);
        }

        #endregion

        #region Events

        #region Overrides

        private void TestForm_Load(object sender, EventArgs e)
        {
            /* Version label */
            var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
            var title = string.Empty;
            if (version.ProductMajorPart == 0 && version.ProductMinorPart == 0 && version.ProductBuildPart == 0)
                title = "Alpha";
            else if (version.ProductMajorPart == 0 && version.ProductMinorPart == 0)
                title = "Beta";
            else
                title = "Release";

            labelVersion.Text = string.Format(
                "{0} {1}.{2}.{3}.{4}",
                title,
                version.ProductMajorPart,
                version.ProductMinorPart,
                version.ProductBuildPart,
                version.ProductPrivatePart);
        }

        protected override void OnLoad(EventArgs e)
        {
            vehicleContainer.Pull();
            mainContainer.Pull();
            backgroundContainer.Panel2Collapsed = true;
            base.OnLoad(e);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (gameControl.IsGameRunning)
                gameControl.TerminateGame();
            e.Cancel = false;
            base.OnClosing(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var rect = new Rectangle(0, Resources.TitleBar2.Height, Width, Height - Resources.TitleBar2.Height);
            var topRect = new Rectangle(0, 0, Width, Resources.TitleBar2.Height);
            e.Graphics.FillRectangle(new LinearGradientBrush(rect, BackColor, Color.FromArgb(255, 102, 0), LinearGradientMode.Vertical), rect);
            e.Graphics.FillRectangle(new LinearGradientBrush(topRect, Color.FromArgb(150, 255, 102, 0), Color.Transparent, LinearGradientMode.Vertical), topRect);
            base.OnPaint(e);
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case (int)WindowsMessages.WM_NCRBUTTONDOWN:
                    //pddNodesTest.Show(this, PointToClient(Cursor.Position));
                    break;

                case (int)WindowsMessages.WM_NCHITTEST:
                    base.WndProc(ref m);
                    if ((int)m.Result == (int)HitTestResults.HTCLIENT)
                    {
                        var cur = PointToClient(new Point(HitTest.GetX(m.LParam), HitTest.GetY(m.LParam)));
                        if (cur.X < mainArea.Left && cur.Y >= mainArea.Top && cur.Y <= mainArea.Bottom)
                            m.Result = (IntPtr)HitTestResults.HTLEFT;
                        else if (cur.X > mainArea.Right && cur.Y >= mainArea.Top && cur.Y <= mainArea.Bottom)
                            m.Result = (IntPtr)HitTestResults.HTRIGHT;
                        else if (cur.Y > mainArea.Bottom && cur.X >= mainArea.Left && cur.X <= mainArea.Right)
                            m.Result = (IntPtr)HitTestResults.HTBOTTOM;
                        else if (cur.X < mainArea.Left && cur.Y < mainArea.Top)
                            m.Result = (IntPtr)HitTestResults.HTTOPLEFT;
                        else if (cur.X > mainArea.Right && cur.Y < mainArea.Top)
                            m.Result = (IntPtr)HitTestResults.HTTOPRIGHT;
                        else if (cur.X < mainArea.Left && cur.Y > mainArea.Bottom)
                            m.Result = (IntPtr)HitTestResults.HTBOTTOMLEFT;
                        else if (cur.X > mainArea.Right && cur.Y > mainArea.Bottom)
                            m.Result = (IntPtr)HitTestResults.HTBOTTOMRIGHT;
                        else
                            m.Result = (IntPtr)HitTestResults.HTCAPTION;
                    }
                    return;
            }

            base.WndProc(ref m);
        }

        #endregion

        #region Buttons

        private void xbMaxSize_Click(object sender, EventArgs e)
        {
            if (xbMaxSize.Text.Equals("+"))
                SetMaxSize();
            else
                SetNormalSize();
        }

        private void xbMinimize_Click(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Minimized;
        }

        private void xbMaximize_Click(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Maximized;
        }

        private void xbClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void xbWebsite_Click(object sender, EventArgs e)
        {
            if (backgroundContainer.Panel2Collapsed)
            {
                if (CheckLogin())
                {
                    backgroundContainer.Panel2Collapsed = false;
                    backgroundContainer.Panel1Collapsed = true;
                }
                else
                {
                    MessageBox.Show(this, @"Please login to the forums to use the application", @"You are not logged in",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            else
            {
                backgroundContainer.Panel1Collapsed = false;
                backgroundContainer.Panel2Collapsed = true;
            }
        }

        private void xbGotoForum_Click(object sender, EventArgs e)
        {
            if (backgroundContainer.Panel1Collapsed)
            {
                backgroundContainer.Panel1Collapsed = false;
                backgroundContainer.Panel2Collapsed = true;
            }

            webBrowser.Navigate(ForumUrl);
        }

        private void xbHelp_Click(object sender, EventArgs e)
        {
            if (backgroundContainer.Panel1Collapsed)
            {
                backgroundContainer.Panel1Collapsed = false;
                backgroundContainer.Panel2Collapsed = true;
            }

            webBrowser.Navigate(WikiPage);
        }

        private void donateButton_Click(object sender, EventArgs e)
        {
            if (backgroundContainer.Panel1Collapsed)
            {
                backgroundContainer.Panel1Collapsed = false;
                backgroundContainer.Panel2Collapsed = true;
            }

            /* Default operation will open in default browser not within the editor */
            webBrowser.Navigate(DonateButton.DonateUrl);
        }

        #endregion

        #region Context menu & popups

        private void xbVehicle_MouseClick(object sender, MouseEventArgs e)
        {
            if (!CheckLogin()) return;

            ppdParts.Hide();
            pddPreferences.Hide();

            if (pddVehicle.Visible)
                pddVehicle.Close(ToolStripDropDownCloseReason.CloseCalled);
            else
                pddVehicle.Show(xbVehicle);
        }

        private void xbVehicle_MouseEnter(object sender, EventArgs e)
        {
            if (!CheckLogin()) return;

            ppdParts.Hide();
            pddPreferences.Hide();

            if (!pddVehicle.Visible)
                pddVehicle.Show(xbVehicle);
        }

        private void xbParts_MouseClick(object sender, MouseEventArgs e)
        {
            if (!CheckLogin()) return;

            pddVehicle.Hide();
            pddPreferences.Hide();

            if (ppdParts.Visible)
                ppdParts.Close(ToolStripDropDownCloseReason.CloseCalled);
            else
                ppdParts.Show(xbParts);
        }

        private void xbParts_MouseEnter(object sender, EventArgs e)
        {
            if (!CheckLogin()) return;

            pddVehicle.Hide();
            pddPreferences.Hide();

            if (!ppdParts.Visible)
                ppdParts.Show(xbParts);
        }

        private void xbPreferences_MouseClick(object sender, MouseEventArgs e)
        {
            if (!CheckLogin()) return;

            pddVehicle.Hide();
            ppdParts.Hide();

            if (pddPreferences.Visible)
                pddPreferences.Close(ToolStripDropDownCloseReason.CloseCalled);
            else
                pddPreferences.Show(xbPreferences);
        }

        private void xbPreferences_MouseEnter(object sender, EventArgs e)
        {
            if (!CheckLogin()) return;

            pddVehicle.Hide();
            ppdParts.Hide();

            if (!pddPreferences.Visible)
                pddPreferences.Show(xbPreferences);
        }

        #endregion

        #region Vehicle popup

        private void pcVehicle_VehicleOpened(object sender, Vehicle e)
        {
            pcVehicle.Close();

            var item = vehiclesMenu.Items.OfType<ImageMenu>().FirstOrDefault(im => ((Vehicle)im.Tag).Name.Equals(e.Name));
            if (item != null) vehiclesMenu.RemoveItem(item);

            if (e == null) return;

            item =
                vehiclesMenu.Items.OfType<ImageMenu>().FirstOrDefault(im => ((Vehicle)im.Tag).Name.Equals(e.Name)) ??
                vehiclesMenu.AddItem(e.Label, e, Resources.Ferrari_64);
            vehiclesMenu.SelectItem(item);
        }

        private void pcVehicle_VehicleSaved(object sender, JBeamLibrary.Vehicle e)
        {
            /* Update game control */
            if (gameControl.IsGameRunning)
                gameControl.UpdateGame();
        }

        #endregion

        #region Preferences popup

        private void pddPreferences_Closed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            pcPreferences.SaveConfig();
        }

        #endregion

        #region Vehicle menu bar

        private void vehiclesMenu_ItemSelected(object sender, ImageMenu e)
        {
            SelectVehicle(e.Tag as Vehicle);
        }

        private void vehiclesMenu_ItemRemoving(object sender, object e)
        {
            var vehicle = e as Vehicle;
            if (vehicle == null) return;

            if (MessageBox.Show(this, @"Would you like to save the vehicle changes ?", @"Save changes ?",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                vehicle.Save(true);
            }
        }

        private void vehiclesMenu_ItemRemoved(object sender, EventArgs e)
        {
            SelectVehicle(null);
        }

        #endregion

        #region Hierarchy control

        private void vehicleHierarchyControl_VehiclePartValidated(object sender, JBeamLibrary.VehicleParts.VehiclePart e)
        {
            SelectVehiclePart(e);
            vehicleContainer.CollapsePanel1();
        }

        #endregion

        #region Tab control

        private void vehiclePartTabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (vehiclePartTabControl.SelectedTab == null) return;

            var ctrl = vehiclePartTabControl.SelectedTab.Controls[0] as VehiclePartControl;
            if (ctrl == null) return;

            ctrl.RefreshData();
        }

        #endregion

        #region Game control

        private void gameControl_RequestSave(object sender, EventArgs e)
        {
            if (_selectedVehicle == null) return;

            /* Save current vehicle */
            _selectedVehicle.Save();

            /* Update the game */
            gameControl.UpdateGame();
        }

        #endregion

        #region Web browser

        private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            /* Next time it will end with a '/' so user can still return to the forum's main page */
            if (webBrowser.Url.AbsoluteUri.Equals(@"http://www.beamng.com/forum") && CheckLogin())
            {
                webBrowser.Navigate(ForumUrl);
            }
        }

        #endregion

        private void pcNodesTest_SelectedNodeChanged(object sender, JBeamLibrary.VehicleParts.Elements.Node e)
        {
            MessageBox.Show(this, string.Format("You selected node {0}", e.Id));
        }

        #endregion

        #region IMessageFilter

        public bool PreFilterMessage(ref Message m)
        {
            var handled = false;
            switch (m.Msg)
            {
                /* KEY UP */
                case (int)WindowsMessages.WM_KEYUP:
                    var key = (Keys)(int)m.WParam & Keys.KeyCode;
                    switch (key)
                    {
                        case Keys.S:
                            if (ModifierKeys.HasFlag(Keys.Control) && _selectedVehicle != null)
                            {
                                handled = true;
                                _selectedVehicle.Save();
                                QuickTipBox.Show(this, "Vehicle saved");
                            }
                            break;
                        case Keys.F4:
                            if (ModifierKeys.HasFlag(Keys.Control) && _selectedVehicle != null)
                            {
                                handled = true;
                                vehiclesMenu.RemoveItemByTag(_selectedVehicle);
                                QuickTipBox.Show(this, "Vehicle closed");
                            }
                            break;
                    }
                    break;
            }
            return handled;
        }

        #endregion
    }
}
